package packageGenerateData;

import packageInputData.DbConnection;

import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayListHandler;

import routine.FunctionLib;
import Jama.*;

public class GenerateDataIWV {

	
	/**
	* function  griddata
	* to calculate the matrix griddata 
	* @param 			lon	double []
	* @param 			lat	double []
	* @param 			iwv	double []
	* @param 			Xi	Matrix
	* @param 			Yi	Matrix
	* @return			Matrix		the result Matrix
	*/
	
	public static Matrix griddata(	double [] lon,
									double [] lat,
									double [] iwv,
									Matrix Xi,
									Matrix Yi)
	{
		
		
	      
	      
		Matrix mat=new Matrix(Xi.getRowDimension(),Xi.getColumnDimension());		
	
		
		double [] lonBis= new double [lon.length];
		double [] latBis= new double [lat.length];
		
		
		
		//for (int i=0;i<lon.length;i++)
			//System.out.println(lon[i]+" ");
		
		Matrix dlon	=new Matrix (lon.length,lon.length);
		Matrix dlonT=new Matrix (lon.length,lon.length);
		Matrix dlat	=new Matrix (lat.length,lat.length);
		Matrix dlatT=new Matrix (lat.length,lat.length);
		
		Matrix d	=new Matrix (lon.length,lon.length);
		Matrix g	=new Matrix (lon.length,lon.length);
		
		Matrix weights =new Matrix (iwv.length,1);
		Matrix gEndMat =new Matrix (1,iwv.length);
		
		Matrix dlonF	=new Matrix (lon.length,lon.length);
		Matrix dlatF	=new Matrix (lon.length,lon.length);
		
		Matrix iwvMat =new Matrix (iwv.length,1);
		
		int y=0;
		
		
		
		
		//initialisation of iwvMat
		for (int i=0;i<iwv.length;i++)
			iwvMat.set(i, 0, iwv[i]);
		
		
		
		
		for (int i=0;i<lon.length;i++)
		{
			for(int j=0;j<lon.length;j++)
			{
				dlon.set(j, i, lon[j]);
				dlonT.set(i, j, lon[j]);
				
				dlat.set(j, i, lat[j]);
				dlatT.set(i,j,lat[j]);
			}
		}
		
		y=0;
		for (int i=0;i<lon.length;i++)
		{
			for(int j=0;j<lon.length;j++)
			{
				dlonF.set(i, j, (dlon.get(i, j)-dlonT.get(i,j)));
				dlatF.set(i, j, (dlat.get(i, j)-dlatT.get(i,j)));
				
				
			}
		}
		
		y=0;
		for (int i=0;i<lon.length;i++)
		{
			for(int j=0;j<lon.length;j++)
			{
				d.set	(i, j, 
							Math.sqrt	(	
										Math.pow((dlonF.get(i, j)),2)+
										Math.pow((dlatF.get(i, j)),2)
										)
						);
				
			}
		}
		List  list1 = new ArrayList(); 
		List  list2 = new ArrayList();
		y=0;
		double ff=1.0;
		for (int i=0;i<lon.length;i++)
		{			
			for(int j=0;j<lon.length;j++)
			{
				 ff=d.get(i, j);
				if(ff==0.0)
				{
					list1.add(i);				
					list2.add(j);
				}
				
				if (i==j)
					d.set(i, j, 1.0);
			}
		}
		
		int abs, ord=0;
		for (int i=0;i<list1.size();i++)
		{
			abs=(Integer) list1.get(i);
			ord=(Integer) list2.get(i);
			
		}
		
		y=0;
		for (int i=0;i<lon.length;i++)
		{
			for(int j=0;j<lon.length;j++)
			{
				g.set(i,j,
						(
								Math.pow(d.get(i, j),2)*
								(Math.log(d.get(i, j))-1)	
								)
						);
			}
		}
		y=0;
		for (int i=0;i<lon.length;i++)
		{			
			for(int j=0;j<lon.length;j++)
			{				
				if ((i==j))
					g.set(i, j, 0.0);
			}
		}
		
		
		for (int i=0;i<list1.size();i++)
		{
			abs=(Integer) list1.get(i);
			ord=(Integer) list2.get(i);	
			
		}
	
	
		
		
		weights= g.solve(iwvMat);
		
		
		y=0;
		double []dEnd=new double [iwv.length];
		double []gEnd=new double [iwv.length];
		
		for (int i=0;i<Xi.getRowDimension();i++)
		{
			for (int j=0;j<Xi.getRowDimension();j++)
			{
				
				for(int k=0;k<lon.length;k++)
				{
					lonBis[k]=Xi.get(i, j)-lon[k];
					latBis[k]=Yi.get(i, j)-lat[k];
				}
				//calculate the abs
				
					for(int cptj=0;cptj<lon.length;cptj++)
					{
						dEnd[cptj]=
									Math.sqrt	(	
												Math.pow((lonBis[cptj]),2)+
												Math.pow((latBis[cptj]),2)
												);
					}
				
					
					for(int cptj=0;cptj<lon.length;cptj++)
					{
						if(dEnd[cptj]!=0)
						{
						gEnd[cptj]= Math.pow(dEnd[cptj], 2)*
									((Math.log(dEnd[cptj]))-1);
						}
						else
							gEnd[cptj]=0;
					}
					//System.out.print("\nEnd.length "+gEnd.length);
					//convertion  gEnd to a matrix
					for(int cptj=0;cptj<gEnd.length;cptj++)
						gEndMat.set(0, cptj, gEnd[cptj]);
					 
					Matrix ggg=gEndMat.times(weights);
					mat.set(i, j, ggg.get(0, 0));
			}	
		}
		return (mat);
	}
	
	/**
	* function  linspace 
	* @param 			startValue	double 
	* @param 			endValue	double 
	* @param 			numberCount	int 
	* @return			double[]		the result array
	*/
	public static double [] linspace (double startValue, double endValue, int numberCount)
	{
		
		double []xi=new double [100];
		double 	start =startValue, 
				end=endValue,
				totalCount=numberCount;		
		double i = start;
		int k=0;
		
		while (i <= end )
		{
			xi[k]=i;
			i += ((end-start)/(totalCount-1));
			k++;
			if(k<totalCount && i>end)				
			{
				xi[k]=end;
			
			}
		}		
		return xi;		
	}
	
	/**
	* function  meshgrid
	* to calculate the matrix meshgrid 
	* @param 			xi	double []
	* @param 			yi	double [] 
	* @return			Matrix []		the result, an array containing 2 Matrix
	*/
	public static Matrix [] meshgrid (double []xi, double [] yi)
	{
		Matrix mat []=new Matrix[2];
		
		mat[0]=new Matrix(yi.length,xi.length);
		mat[1]=new Matrix(yi.length,xi.length);
		
		for(int i=0;i<yi.length;i++)
			for (int j=0;j<xi.length;j++)
				mat[0].set(i, j, xi[j]);		
		
		for(int i=0;i<yi.length;i++)
			for (int j=0;j<xi.length;j++)
				mat[1].set(i, j, yi[i]);

		return mat;		
	}
	/**
	 * function 
	 * to generate IWV data and put it into the database
	 * @return			void
	*/
	@SuppressWarnings({ "deprecation", "rawtypes" })
	public static void generateIWV ()
	{
		//to contain zwd data
		ArrayList <Integer> zwdDoy =new ArrayList<Integer>();
		ArrayList <Integer> zwdEpok =new ArrayList<Integer>();
		ArrayList <Double> zwdValue =new ArrayList<Double>();
		ArrayList <Double> zwdSigValue =new ArrayList<Double>();
		//to contain iwv data
		ArrayList <Integer> iwvDoy =new ArrayList<Integer>();
		ArrayList <Integer> iwvEpok =new ArrayList<Integer>();
		ArrayList <Double> iwvValue =new ArrayList<Double>();
		ArrayList <Double> iwvSigValue =new ArrayList<Double>();
		
		List 	list1 = new ArrayList(), 
				list2 = new ArrayList(), 
				list3 = new ArrayList();
		
		double [] tempPTU2=new double [96];
		double [] PI=new double [96];		
		double sigPI=0;
		
	  	String siteName="",req="";
	  	int inserts=0;
		
	  	//connect to the database
	  	Connection conn=DbConnection.connectDB();					  			
	  	QueryRunner qRunner = new QueryRunner();
		
		//get GPS code list from sites_gps in list1 then in data[]
		try {
		       list1 =(List) qRunner.query(conn,
							    		   "select code from sites_gps",
							    		   new ArrayListHandler());
		} catch (SQLException e2) {
		       e2.printStackTrace();
		}		
		//loop gps sites
		for(int cptgps=0;cptgps<list1.size();cptgps++)
		{
			Object data[] = (Object[]) list1.get(cptgps);
			siteName=data[0].toString().toUpperCase();
			//System.out.println("Station in process: "+siteName);			
			
			//get zwd value
			//execute query
			try {
				req=	"select doy,epok,zwd,sigzwd from zwd where site=?  and session_id= "+
						MainClass.session;
				list2 =(List) qRunner.query(conn,
							    		   req,
							    		   siteName,
							    		   new ArrayListHandler());						
			} catch (SQLException e2) {
		      // e2.printStackTrace();
		
			}
			//get the result
			if(list2.size()>0)
			{
				for(int cptzwd=0;cptzwd<list2.size();cptzwd++)
				{
					Object data2[] = (Object[]) list2.get(cptzwd);
					zwdDoy.add(Integer.parseInt(data2[0].toString()));
					zwdEpok.add(Integer.parseInt(data2[1].toString()));
					zwdValue.add(Double.parseDouble(data2[2].toString()));
					zwdSigValue.add(Double.parseDouble(data2[3].toString()));
				}
			}			
			
			//get ptu2 value
			//execute query
			try {
				req="select temp from ptu2 where site=?  and session_id= "+MainClass.session;
				list3 =(List) qRunner.query(conn,
							    		   req,
							    		   siteName,
							    		   new ArrayListHandler());						
			} catch (SQLException e2) {
		       e2.printStackTrace();
		
			}
			//get the result
			if(list3.size()>0)
			{
				for(int cptptu2=0;cptptu2<list3.size();cptptu2++)
				{
					Object data3[] = (Object[]) list3.get(cptptu2);
					tempPTU2[cptptu2]=(Double.parseDouble(data3[0].toString()));
					
				}
			}			
			
			for(int j=0;j<3*list2.size();j++)
			{			
				PI[j]=FunctionLib.calcQ(tempPTU2[j], "med");
			}
			int k=0,p=0;
			//for (int j=0;j<3;j++)			
			//{
				for (int i=0;i<list2.size();i++)
				{			
					p=k+i;
					iwvValue.add((zwdValue.get(i)/PI[p]));
					sigPI=iwvValue.get(i)*0.01;
					iwvSigValue.add((
							Math.sqrt((
							Math.pow((zwdSigValue.get(i)/PI[p]),2)+
							Math.pow(sigPI, 2))						
							)));
					iwvDoy.add(zwdDoy.get(i));
					iwvEpok.add(zwdEpok.get(i));
				}
				k+=list2.size();				
			//}
			
			for (int i=0;i<iwvDoy.size();i++)
			{
				//prepare query
				req="INSERT INTO iwv" +
						"(session_id,doy,epok,iwv,sigiwv,site)" +				
						"VALUES (?,?,?,?,?,?)";
				//execute query
				 try {
						inserts = qRunner.update(conn,req,
									MainClass.session,
									iwvDoy.get(i),
									iwvEpok.get(i),
									iwvValue.get(i),
									iwvSigValue.get(i),
									siteName);
						
				 } catch (SQLException e) {									
						e.printStackTrace();
				 }
				
			}
			//clear list for the next iteration
			list2.clear();
			list3.clear();
			zwdDoy.clear();
			zwdValue.clear();
			zwdEpok.clear();
			zwdSigValue.clear();
			iwvDoy.clear();
			iwvValue.clear();
			iwvEpok.clear();
			iwvSigValue.clear();
			
		}		
		
		//check if insertion is done properly
		 if (inserts==1)
			{
 				System.out.println("\tInsertion in iwv done ");
 				inserts=0;
			}
		//close connection
		DbUtils.closeQuietly(conn);
	}	
	/**
	 * function 
	 * to generate GraphIWV data and put it into the database
	 * @return			void
	*/
	@SuppressWarnings({ "deprecation", "rawtypes" })
	public static void generateGraphIWV ()
	{
		
	  	List list1 = new ArrayList();
		List list2 = new ArrayList();
				
		String req = "",siteName="";
		int inserts=0;
		
		//connect to the database
		Connection conn=DbConnection.connectDB();					  			
	  	QueryRunner qRunner = new QueryRunner();
	  	
	  	//get data from  table "param"
	  	int paramDoy= 		(Integer)(DbConnection.getFromDB("doy", "param"));
		int paramEpokDeb= 	(Integer)(DbConnection.getFromDB("epok_deb", "param"));
		int paramEpokEnd= 	(Integer)(DbConnection.getFromDB("epok_fin", "param"));
		int paramEpokInc= 	(Integer)(DbConnection.getFromDB("epok_inc", "param"));
	
		//get GPS code list from sites_gps in list1 then in data[]
		try {
		       list1 =(List) qRunner.query(conn,
							    		   "select code from sites_gps",
							    		   new ArrayListHandler());
		} catch (SQLException e2) {
		       e2.printStackTrace();
		}
		for (int epok=paramEpokDeb;epok<=paramEpokEnd;epok+=paramEpokInc)
		{
			for(int j=0;j<list1.size();j++)
			{
				Object data[] = (Object[]) list1.get(j);					
				siteName=data[0].toString().toUpperCase();
				//get iwv value
				//execute query
				try {
					req="select iwv,sigiwv from iwv where site=? and epok="+epok+" and session_id= "+MainClass.session;
					list2 =(List) qRunner.query(conn,
								    		   req,
								    		   siteName,
								    		   new ArrayListHandler());
				} catch (SQLException e2) {
					e2.printStackTrace();
			
				}
				//get the result
				if(list2.size()>0)
				{
					for (int i=0;i<list2.size();i++)
					{
						Object data2[] = (Object[]) list2.get(i);
						//prepare query
						req="INSERT INTO prep_iwv_graph" +
								"(session_id,lon,lat,alt,iwv,sigiwv,epok_time,doy)" +				
								"VALUES (?,?,?,?,?,?,?,?)";
						//execute query
						try {
							inserts = qRunner.update(conn,req,
										MainClass.session,
										(Double)(DbConnection.getFromDB("lon", "sites_all","code",siteName)),
										(Double)(DbConnection.getFromDB("lat", "sites_all","code",siteName)),
										(Double)(DbConnection.getFromDB("alt", "sites_all","code",siteName)),
										Double.parseDouble(data2[0].toString()),
										Double.parseDouble(data2[1].toString()),
										epok,
										paramDoy);
						} catch (SQLException e) {									
							e.printStackTrace();
						}
					}
				}
				list2.clear();
			}
			//check if insertion is done properly
			if (inserts==1)
			{
  				System.out.println("\tInsertion in prep_iwv_graph for epok "+epok +" done ");
  				inserts=0;
			}
		}
		//close connection
		DbUtils.closeQuietly(conn);
	}
	//function griddata under construction, due to function griddata 
	/**
	 * function 
	 * to generate InterpIWV data and put it into the database
	 * @return			void
	*/
	
	@SuppressWarnings("rawtypes")
	public static void generateInterpIWV ()
	{
		
		double 	latmin=(Double)(DbConnection.getFromDB("latmin", "param"));
		double 	latmax=(Double)(DbConnection.getFromDB("latmax", "param"));
		int 	nlat=(Integer)(DbConnection.getFromDB("nlat", "param"));
		
		double 	lonmin=(Double)(DbConnection.getFromDB("lonmin", "param"));
		double 	lonmax=(Double)(DbConnection.getFromDB("lonmax", "param"));
		int 	nlon=(Integer)(DbConnection.getFromDB("nlon", "param"));
		
		int 	altmin=(Integer)(DbConnection.getFromDB("altmin", "param"));
		int 	altmax=(Integer)(DbConnection.getFromDB("altmax", "param"));
		int 	nalt=(Integer)(DbConnection.getFromDB("nalt", "param"));
		
		int paramDoy= 		(Integer)(DbConnection.getFromDB("doy", "param"));
		int paramEpokDeb= 	(Integer)(DbConnection.getFromDB("epok_deb", "param"));
		int paramEpokEnd= 	(Integer)(DbConnection.getFromDB("epok_fin", "param"));
		int paramEpokInc= 	(Integer)(DbConnection.getFromDB("epok_inc", "param"));
		
		Date paramDate=	(Date)(DbConnection.getFromDB("date", "param"));
		int paramYear=	paramDate.getYear()+1900;
		int paramDay=	paramDate.getDate();
		int paramMonth=	paramDate.getMonth()+1;
		String monthName="";
		int inserts=0;
		
		Matrix FinalGrid=new Matrix (100,100);
		
		
		switch (paramMonth)
		{
					case 1: monthName="January";
					case 2: monthName="February";
					case 3: monthName="March";
					case 4: monthName="April";
					case 5: monthName="May";
					case 6: monthName="June";
					case 7: monthName="July";
					case 8: monthName="August";
					case 9: monthName="September";
					case 10: monthName="October";
					case 11: monthName="November";
					case 12: monthName="December";
		}
		
		
		Connection conn=DbConnection.connectDB();					  			
	  	QueryRunner qRunner = new QueryRunner();
	  	String req="";
		
	  	List list1 = new ArrayList();
		
		double []X;
		double []Y;
		double []V;
		
		for (int epok=paramEpokDeb;epok<=paramEpokEnd;epok+=paramEpokInc)
		{
			//get  data list from prep_iwv_graph
			
			req="select lat,lon,iwv from prep_iwv_graph where epok_time= "+epok+" and doy= "+paramDoy+" and session_id= "+MainClass.session;
			try {
			       list1 =(List) qRunner.query(conn,
								    		   req,
								    		   new ArrayListHandler());
			} catch (SQLException e2) {
			       e2.printStackTrace();
			}
			
			X=new double [list1.size()];
			Y=new double [list1.size()];
			V=new double [list1.size()];
	
			int cptv=0;
			for(int j=0;j<list1.size();j++)
			{
				Object data1[] = (Object[]) list1.get(j);
				X[cptv]=Double.parseDouble(data1[0].toString());
				Y[cptv]=Double.parseDouble(data1[1].toString());
				V[cptv]=Double.parseDouble(data1[2].toString())*1000;
				cptv++;
			}
			
					double []xi=new double [100];
					double []yi=new double [100];
					
					 xi=linspace(lonmin,lonmax,100);
					 yi=linspace(latmin,latmax,100);

				 	Matrix mat []=new Matrix[2];
					mat[0]=new Matrix(100,100);
					mat[1]=new Matrix(100,100);				
					mat=meshgrid(xi,yi);
			
					FinalGrid=griddata(Y,X,V,mat[0],mat[1]);
					
					req="INSERT INTO interp_iwv" +
							"(session_id,abs,ord,value,epok_time,doy)" +				
							"VALUES (?,?,?,?,?,?)";
					
					for (int i=0;i<100;i++)
					{						
						for(int j=0;j<100;j++)
						{
							try {
								inserts = qRunner.update(conn,req,
											MainClass.session,
											i,
											j,
											FinalGrid.get(i, j),
											epok,
											paramDoy);
							} catch (SQLException e) {									
								e.printStackTrace();
							}
							
						}
					}
					
					//check if insertion is done properly
					if (inserts==1)
					{
		  				System.out.println("\tInsertion in interp_iwv for epok "+epok +" done ");
		  				inserts=0;
					}			
		}
		
				//close connection
				DbUtils.closeQuietly(conn);
	}
	
	/**
	 * function 
	 * to generate SIWV data and put it into the database
	 * @return			void
	*/
	@SuppressWarnings({ "deprecation", "rawtypes" })
	public static void generateSIWV ()

	{		
		List list1 = new ArrayList();
		List list2 = new ArrayList();
		List list3 = new ArrayList();
		
		double coord [][]=new double [3][1];
		
		String siteName="",req="";
		int inserts=0,nsat=0,index=0;
		
		double dlat=0,dalt=0,dlon=0,
				sl=0,az=0,el=0,
				temp=0,zhd=0,
				hmap=0,swd=0,
				siwv=0,pi=0,
				x[]=new double [1],
				y[]=new double [1],
				z[]=new double [1];
		
		//connect to the database
		Connection conn=DbConnection.connectDB();					  			
	  	QueryRunner qRunner = new QueryRunner();
	  	
	  	//get data from table "param"
	  	int paramDoy= 		(Integer)(DbConnection.getFromDB("doy", "param"));
		int paramEpokDeb= 	(Integer)(DbConnection.getFromDB("epok_deb", "param"));
		int paramEpokEnd= 	(Integer)(DbConnection.getFromDB("epok_fin", "param"));
		int paramEpokInc= 	(Integer)(DbConnection.getFromDB("epok_inc", "param"));
	
		for (int epok=paramEpokDeb;epok<=paramEpokEnd;epok+=paramEpokInc)
		{
			//get epok_id and sta_name from vcopsepok value
			try {
				req="select epok_id,sta_name from vcopsepok where epok_time="+epok+" and session_id= "+MainClass.session;
				list1 =(List) qRunner.query(conn,
							    		   req,
							    		   new ArrayListHandler());						
			} catch (SQLException e2) {
		       e2.printStackTrace();		
			}
			
			if(list1.size()>0)
			{
				for(int j=0;j<list1.size();j++)
				{
					Object data[] = (Object[]) list1.get(j);					
					siteName=data[1].toString().toUpperCase();
					//calculate geoc coordinates from geo ones on sites_all
					dlat=(Double)DbConnection.getFromDB("lat", "sites_all", "code", siteName);
					dalt=(Double)DbConnection.getFromDB("alt", "sites_all", "code", siteName);
					dlon=(Double)DbConnection.getFromDB("lon", "sites_all", "code", siteName);
					
					x[0]=dlat;
					y[0]=dalt;
					z[0]=dlon;		
					
					coord=FunctionLib.geo2geoc(z,x,y);
					siteName=data[1].toString().toUpperCase();
					//get data from ptu2 value
					try {
						req=	"select temp from ptu2 where site=?  and session_id= "+
								MainClass.session;
						list2 =(List) qRunner.query(conn,
									    		   req,
									    		   siteName,
									    		   new ArrayListHandler());
					} catch (SQLException e2) {
					       e2.printStackTrace();
					}
					
					if(list2.size()>0)
					{				
						//get data from zhd value
						try {
							req="select zhd from zhd where site=?"+" and session_id= "+MainClass.session;
							list3 =(List) qRunner.query(conn,
										    		   req,
										    		   siteName,
										    		   new ArrayListHandler());
						} catch (SQLException e2) {
						       e2.printStackTrace();	
						}
						
						if(list3.size()>0)
						{
							index=epok/30;
							sl=		(Double)DbConnection.getFromDB("sl", "epok", "id",Integer.parseInt(data[0].toString()));
							az=		(Double)DbConnection.getFromDB("az", "epok", "id",Integer.parseInt(data[0].toString()));
							el=		(Double)DbConnection.getFromDB("el", "epok", "id",Integer.parseInt(data[0].toString()));
							nsat=	(Integer)DbConnection.getFromDB("sat", "epok", "id",Integer.parseInt(data[0].toString()));
							
							Object data2[] = (Object[]) list2.get(index-1);					
							temp=(Double)data2[0];
							
							Object data3[] = (Object[]) list3.get(index-1);					
							zhd=(Double)data3[0];
							
							pi=FunctionLib.calcQ(temp, "med");
							hmap=FunctionLib.MAPF(paramDoy, dalt, dlat, el, "NMFH");
							swd=sl-zhd*hmap;
							siwv=swd/pi;
							
							//prepare query
							req="INSERT INTO siwv" +
									"(session_id,siwv,xsta,ysta,zsta,az,el,epok,nsat,site)" +				
									"VALUES (?,?,?,?,?,?,?,?,?,?)";
							//execute query
							try {
								inserts = qRunner.update(conn,req,
											MainClass.session,
											siwv,
											coord[0][0],
											coord[1][0],
											coord[2][0],
											az,
											el,
											epok,
											nsat,
											siteName);
							} catch (SQLException e) {									
								e.printStackTrace();
							}
						}
					}
				}
			}
			//test is insertion is done properly
			if (inserts==1)
			{
  				System.out.println("\tInsertion in siw for epok "+epok +" done ");
  				inserts=0;
			}
			//End loop for epok
		}
		//close connection
		DbUtils.closeQuietly(conn);
	}
	
	
}
